有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

性能记录屏幕Java磁盘速度

我正在开发一个Java应用程序来记录屏幕。我用一个机器人拍摄了几个屏幕截图,保存到一个临时文件夹中,然后用JpegImagesToMovie。java将它们构建到QuickTime电影文件中

我遇到的问题是,尽管将脚本开发为以20fps的速度运行,但我只能实现5fps左右的速度。我一直在跟踪磁盘速度,因为将映像保存到磁盘所花的时间太长,这会占用脚本的其余部分

接下来,我修改了脚本,将图像存储在一个BufferedImages数组中,然后在停止录制后将其写入磁盘,从而固定了帧速率,但是在重新编码时,Java会很快耗尽内存(录制几秒钟后)

有没有人有这样做的想法或经验。我能想到的一个解决方案是,是否有办法增加JPEG图像的压缩,但我不确定如何做到这一点

任何帮助都将不胜感激


共 (2) 个答案

  1. # 1 楼答案

    您可能要考虑的一个选项是对多个线程进行处理。一个线程可以专用于截图,许多其他线程可以写入磁盘。由于写入磁盘不是CPU密集型操作,因此可以让多个磁盘同时运行,每个磁盘都写入不同的文件。以下程序在我的计算机上运行良好,堆大小为512M:

    import javax.imageio.ImageIO;
    import java.awt.*;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;
    import java.util.concurrent.*;
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class ImageWritingMain
    {
      public static void main(String[] args) throws Exception
      {
        // a queue
        final BlockingQueue<BufferedImage> queue = 
            new LinkedBlockingQueue<BufferedImage>();
    
        // schedule a thread to take 20 images per second and put them in 
        // the queue
        int fps = 20;
        final ScreenShotRecorder recorder = 
            new ScreenShotRecorder(new Robot(), queue);
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(recorder, 0, (1000L/fps));
    
        // make a directory to hold the screenshot images
        String id = new Date().toString().replace(' ', '-').replace(':', '-');
        File imageDir = new File("images-" + id);
        imageDir.mkdirs();
    
        // start 10 threads, and each thread reads from the queue and 
        // writes the image to a file
        int nWriterThreads = 10;
        ExecutorService threadPool = Executors.newFixedThreadPool(nWriterThreads);
        for (int i = 0; i < nWriterThreads; i++)
        {
          ImageWriter task = new ImageWriter(queue, imageDir);
          threadPool.submit(task);
        }
        System.out.println("Started all threads ..");
    
        // wait as long as you want the program to run (1 minute, for example) ...
        Thread.sleep(60 * 1000L);
        // .. and shutdown the threads
        System.out.println("Shutting down all threads");
        threadPool.shutdownNow();
        timer.cancel();
    
        if (! queue.isEmpty())
        {
          System.out.println("Writing " + queue.size() + " remaining images");
          // write the remaining images to disk in the main thread
          ImageWriter writer = new ImageWriter(queue, imageDir);
          BufferedImage img = null;
          while ((img = queue.poll()) != null)
          {
            writer.writeImageToFile(img);
          }
        }
      }
    }
    
    class ScreenShotRecorder extends TimerTask
    {
      private static final Rectangle screenRect = 
          new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
      private static final AtomicInteger counter = new AtomicInteger();
      private final Robot robot;
      private final BlockingQueue<BufferedImage> imageQueue;
    
      ScreenShotRecorder(Robot robot, BlockingQueue<BufferedImage> imageQueue)
      {
        this.robot = robot;
        this.imageQueue = imageQueue;
      }
    
      @Override
      public void run()
      {
        try
        {
          BufferedImage image = robot.createScreenCapture(screenRect);
          imageQueue.put(image);
          System.out.println(Thread.currentThread() + 
              ": Took screenshot #" + counter.incrementAndGet());
        }
        catch (InterruptedException e)
        {
          System.out.println("Finishing execution of " + Thread.currentThread());
          return;
        }
        catch (Exception e)
        {
          e.printStackTrace();
        }
      }
    }
    
    class ImageWriter implements Runnable
    {
      private static final AtomicInteger counter = new AtomicInteger();
      private final BlockingQueue<BufferedImage> imageQueue;
      private final File dir;
    
      ImageWriter(BlockingQueue<BufferedImage> imageQueue, File dir)
      {
        this.imageQueue = imageQueue;
        this.dir = dir;
      }
    
      @Override
      public void run()
      {
        while (true)
        {
          try
          {
            BufferedImage image = imageQueue.take();
            writeImageToFile(image);
          }
          catch (InterruptedException e)
          {
            System.out.println("Finishing execution of " + Thread.currentThread());
            return;
          }
          catch (Exception e)
          {
            e.printStackTrace();
          }
        }
      }
    
      public void writeImageToFile(BufferedImage image) throws IOException
      {
        File file = new File(dir, "screenshot-" + counter.incrementAndGet());
        ImageIO.write(image, "JPG", file);
        System.out.println(Thread.currentThread() + 
            ": Wrote " + file.getCanonicalPath());
      }
    }
    
  2. # 2 楼答案

    米利穆斯说的。也许你可以设法降低JPEG的分辨率,给你多一点内存,但你可能不得不使用视频编解码器。您还可以尝试创建一个处理程序,以便仅在移动鼠标时进行录制,或者如果您确实想用JPEG进行录制,则可以键入